﻿using System;
using System.Text;
using System.Threading.Tasks;
using System.Web.UI;
using kmer.Helper;

// ReSharper disable once CheckNamespace
namespace com.kmer {
	/// <summary>
	/// 日志输出类
	/// 现在是输出到文本
	/// </summary>
	public static class Log {
		/// <summary>
		/// 日志类型
		/// </summary>
		public enum LogType {
			/// <summary>
			/// 一般性日志
			/// </summary>
			LOG,
			/// <summary>
			/// 比较特别的日志
			/// </summary>
			INFO,
			/// <summary>
			/// 警告：可能会发生错误的地方
			/// </summary>
			WARMING,
			/// <summary>
			/// 错误：一般性错，例如：捕获到异常，或者判断到异常（比如：if(变量==null)）
			/// </summary>
			ERROR,
			/// <summary>
			/// 严重错误：导致操作无法正常进行（比如保存数据失败）
			/// </summary>
			FAIL,
			/// <summary>
			/// 严重错误：导致系统崩溃的
			/// </summary>
			CRASH = 99
		}
		private static string _lastLogFile = "";
		private static System.Collections.Generic.Dictionary<LogType, string> _lastLogFileDir = new System.Collections.Generic.Dictionary<LogType, string>();
		const long MaxFileLength = 1024 * 100;
	    private static string _logPath = "";
		static string GetLogFile() {
			var path = string.IsNullOrWhiteSpace(_logPath)
                        ? (_logPath = System.Web.HttpContext.Current.Server.MapPath("~/App_Data/Log"))
                        : _logPath;
			if (System.IO.Directory.Exists(path) == false) {
				System.IO.Directory.CreateDirectory(path);
			}
			if (string.IsNullOrWhiteSpace(_lastLogFile)) {
				_lastLogFile = System.IO.Path.Combine(path, DateTime.Now.ToString("yyyy-MM-dd") + ".txt");
			}
			var index = 1;
			while (System.IO.File.Exists(_lastLogFile)) {
				var file = new System.IO.FileInfo(_lastLogFile);
				if (file.Length > MaxFileLength) {
					_lastLogFile = System.IO.Path.Combine(path, DateTime.Now.ToString("yyyy-MM-dd") + "_" + index + ".txt");
					index++;
				} else {
					break;
				}
			}
			return _lastLogFile;
		}
		static string GetLogFile(LogType type) {
			var path = _logPath;
			if (string.IsNullOrWhiteSpace(_logPath)) {
				_logPath = System.Web.HttpContext.Current.Server.MapPath("~/App_Data/Log");
				if (System.IO.Directory.Exists(_logPath) == false) {
					System.IO.Directory.CreateDirectory(_logPath);
				}
				path = _logPath;
			}
			var prex = $"{type}_";
			var lastLogFile = _lastLogFileDir.ContainsKey(type) ? _lastLogFileDir[type] : string.Empty;
			if (string.IsNullOrWhiteSpace(lastLogFile)) {
				lastLogFile = System.IO.Path.Combine(path, prex + DateTime.Now.ToString("yyyy-MM-dd") + ".txt");
			}
			var index = 1;
			while (System.IO.File.Exists(lastLogFile)) {
				var file = new System.IO.FileInfo(lastLogFile);
				if (file.Length > MaxFileLength) {
					lastLogFile = System.IO.Path.Combine(path, prex + DateTime.Now.ToString("yyyy-MM-dd") + "_" + index + ".txt");
					index++;
				} else {
					break;
				}
			}
			_lastLogFileDir[type] = lastLogFile;
			return lastLogFile;
		}
		/// <summary>
		/// 输出日志：多行
		/// </summary>
		/// <param name="lines"></param>
		public static void WriteLines(params object[] lines) {
			if (lines == null || lines.Length < 1) return;
			WriteLog(lines.Join(Environment.NewLine));
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="lines"></param>
		/// <returns></returns>
		public static async Task WriteLinesAsync(params object[] lines) {
			if (lines == null || lines.Length < 1) return;
			await WriteLogAsync(lines.Join(Environment.NewLine));
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="strMemo"></param>
		/// <param name="tag"></param>
		/// <param name="type"></param>
		/// <returns></returns>
		public static async Task WriteLogAsync(string strMemo, string tag = "Normal", LogType type = LogType.LOG){
			await Task.Run(() =>{
				WriteLog(strMemo, tag, type);
			});
		}
		/// <summary>
		/// 输出日志
		/// </summary>
		/// <param name="strMemo">日志内容</param>
		/// <param name="tag">标签，用于检索日志时方便进行过滤</param>
		/// <param name="type">类型</param>
		public static void WriteLog(string strMemo, string tag = "Normal", LogType type = LogType.LOG) {
			//#if DEBUG
			try {
				var sb = new StringBuilder();
				sb.AppendLine("----------------------------------------------------------");
				sb.AppendLine(string.Format("{0}：{2}:{1},{1:fffff}", type, DateTime.Now, tag));
				sb.AppendLine("----------------------------------------------------------");
				sb.AppendLine(strMemo);
				sb.AppendLine("=END=LOG==================================================");

				var filename = GetLogFile(type);
				lock (filename){
					//临时锁定
					using (
						var sr = !System.IO.File.Exists(filename)
							? System.IO.File.CreateText(filename)
							: System.IO.File.AppendText(filename))
					{
						sr.WriteLineAsync(sb.ToString());
					}
				}
			} catch {
				// ignored
			//} finally{
				//sr?.Close();
			}
			//#endif
		}
		/// <summary>
		/// 输出日志
		/// </summary>
		/// <param name="str">日志内容</param>
		/// <param name="tag">标签，用于检索日志时方便进行过滤</param>
		/// <param name="type">类型</param>
		/// <param name="args"></param>
		public static void WriteLog(string str, string tag = "Normal", LogType type = LogType.LOG, params object[] args) {
			WriteLog(args.Length > 0 ? string.Format(str, args) : str, tag, type);
		}
		/// <summary>
		/// 输出错误日志（Type=LogType.ERROR）
		/// </summary>
		/// <param name="str">日志内容</param>
		/// <param name="tag">标签，用于检索日志时方便进行过滤</param>
		/// <param name="args"></param>
		public static void Error(string str, string tag = "Normal", params object[] args) {
			WriteLog(args.Length > 0 ? string.Format(str, args) : str, tag, LogType.ERROR);
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="lines"></param>
		public static void ErrorLines(params object[] lines) {
			WriteLog(lines.Join(Environment.NewLine), "ERROR", LogType.ERROR);
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="exception"></param>
		/// <param name="tag"></param>
		public static void Error(Exception exception, string tag = "Exception") {
			WriteLog("发生错误：{0}\n{1}\n{2}", tag, LogType.ERROR, exception.Message, exception.Source, exception.StackTrace);
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="txt"></param>
		/// <param name="exception"></param>
		/// <param name="tag"></param>
		public static void Error(string txt, Exception exception, string tag = "Exception") {
			WriteLog("{3} 发生错误：{0}\n{1}\n{2}", tag, LogType.ERROR, exception.Message, exception.Source, exception.StackTrace, txt);
		}
		/// <summary>
		/// 输出错误日志（Type=LogType.CRASH）
		/// </summary>
		/// <param name="str">日志内容</param>
		/// <param name="tag">标签，用于检索日志时方便进行过滤</param>
		/// <param name="args"></param>
		public static void Crash(string str, string tag = "Normal", params object[] args) {
			WriteLog(args.Length > 0 ? string.Format(str, args) : str, tag, LogType.CRASH);
		}

		#region 扩展方法
		/// <summary>
		/// 
		/// </summary>
		/// <param name="page"></param>
		/// <param name="str"></param>
		/// <param name="tag"></param>
		/// <param name="args"></param>
		public static void Info(this Page page, string str, string tag = "Normal", params object[] args) {
			WriteLog(args.Length > 0 ? string.Format(str, args) : str, tag, LogType.INFO);
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="page"></param>
		/// <param name="txt"></param>
		/// <param name="tag"></param>
		/// <param name="args"></param>
		public static void Err(this Page page, string txt, string tag = "Normal", params object[] args) {
			WriteLog(args.Length > 0
						? $"{page.Request.RawUrl}\n{txt} {args}"
						: $"{page.Request.RawUrl}\n{txt} ",
				tag,
				LogType.ERROR);
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="page"></param>
		/// <param name="exception"></param>
		/// <param name="tag"></param>
		public static void Err(this Page page, Exception exception, string tag = "Exception") {
			WriteLog("{3}\n发生错误：{0}\n{1}\n{2}",
				tag,
				LogType.ERROR,
				exception.Message,
				exception.Source,
				exception.StackTrace,
				page.Request.RawUrl);
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="page"></param>
		/// <param name="txt"></param>
		/// <param name="exception"></param>
		/// <param name="tag"></param>
		public static void Err(this Page page, string txt, Exception exception, string tag = "Exception") {
			WriteLog("{4}\n{3} 发生错误：{0}\n{1}\n{2}",
				tag,
				LogType.ERROR,
				exception.Message,
				exception.Source,
				exception.StackTrace,
				txt,
				page.Request.RawUrl);
		}
		#endregion
	}
}
